﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.Communication.Net.MQBase
{
    /// <summary>
    /// MQ插件管理器
    /// </summary>
    public class MQMessageQueueFactoryManager
    {
        private static readonly Dictionary<string, IMQMessageQueueFactory> _factoryDic;

        static MQMessageQueueFactoryManager()
        {
            _factoryDic = new Dictionary<string, IMQMessageQueueFactory>();
        }


        /// <summary>
        /// 初始化MQ插件管理器
        /// </summary>
        /// <param name="mqPluginDir">MQ插件目录</param>
        public static void Init(string mqPluginDir)
        {
            //const string mqPlugindir = "MQPlugin";
            //var dir = Path.GetDirectoryName(typeof(MessageQueueFactoryManager).Assembly.Location);
            //string mqPluginDir = Path.Combine(dir, mqPlugindir);
            string[] dllFilePathArr = Directory.GetFiles(mqPluginDir, "*.dll", SearchOption.AllDirectories);
            List<string> assemblyNameList = AppDomain.CurrentDomain.GetAssemblies().Select(t => { return t.FullName; }).ToList();
            Type imessageQueueFactoryType = typeof(IMQMessageQueueFactory);

            foreach (var dllFilePath in dllFilePathArr)
            {
                try
                {
                    var assemblyName = AssemblyEx.GetAssemblyName(dllFilePath);
                    if (assemblyNameList.Contains(assemblyName))
                    {
                        continue;
                    }

                    assemblyNameList.Add(assemblyName);
                    var assembly = Assembly.LoadFrom(dllFilePath);
                    Type[] typeArr = assembly.GetExportedTypes();
                    foreach (var type in typeArr)
                    {
                        if (!type.IsClass ||
                        type.IsAbstract ||
                        type.GetInterface(imessageQueueFactoryType.FullName) == null ||
                        type.GetConstructors().Where(t => { return t.GetParameters().Length == 0; }).Count() == 0)
                        {
                            //非类、抽象类、类型未实现IMessageQueueFactoryType接口、没有无参构造函数,忽略
                            continue;
                        }

                        IMQMessageQueueFactory messageQueueFactory = (IMQMessageQueueFactory)Activator.CreateInstance(type);
                        _factoryDic.Add(messageQueueFactory.Name, messageQueueFactory);
                    }
                }
                catch (BadImageFormatException)
                {
                    //非clr程序集
                    continue;
                }
                catch (Exception ex)
                {
                    ZLoger.Error(ex);
                }
            }
        }

        /// <summary>
        /// 添加工厂对象
        /// </summary>
        /// <param name="fatcory">工厂对象</param>
        /// <exception cref="ArgumentNullException">工厂对象为null</exception>
        public static void AddFatcory(IMQMessageQueueFactory fatcory)
        {
            if (fatcory == null)
            {
                throw new ArgumentNullException(nameof(fatcory));
            }

            if (string.IsNullOrWhiteSpace(fatcory.Name))
            {
                throw new ArgumentNullException(nameof(fatcory.Name));
            }

            _factoryDic.Add(fatcory.Name, fatcory);
        }

        /// <summary>
        /// 根据消息队列工厂名称获取消息队列工厂
        /// </summary>
        /// <param name="name">消息队列工厂名称</param>
        /// <returns>消息队列工厂</returns>
        public static IMQMessageQueueFactory GetFatcoryByName(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            IMQMessageQueueFactory fatcory;
            if (_factoryDic.TryGetValue(name, out fatcory))
            {
                return fatcory;
            }

            return null;
        }

    }
}
